#include "Metgine/Graphics/ParticleSystem.hpp"
#include <SFML/System/Randomizer.hpp>

namespace Metgine
{
namespace Graphics
{

ParticleSystem::ParticleSystem(ImageResource* imageResource, float life, float gravity, float wind) :
    Effect(life),
    m_gravity(Vector2f(gravity, wind))
{
    m_numParticles = 0;

    m_imageResource = imageResource;

    m_spawnTimer = 0.0f;
    m_spawnTime = 0.005f;

}

ParticleSystem::~ParticleSystem()
{

}

void ParticleSystem::Update(float elapsedTime)
{
    if ((m_life > 0.0f) || (m_numParticles > 0))
    {
        // Update existing particles
        sf::Uint32 i = 0;
        while (i < m_numParticles)
        {
            if (m_particles[i].m_life > 0.0f)
            {
                UpdateParticle(&m_particles[i], elapsedTime);
                i ++;
            }
            else
            {
                // Copy last particle to this one
                m_particles[i] = m_particles[m_numParticles - 1];
                m_numParticles--;
            }
        }

        if (m_life > 0.0f)
        {
            // Spawn new particles
            m_spawnTimer += elapsedTime;
            while (m_spawnTimer >= m_spawnTime)
            {
                // Add a new particle if we have no dead ones to replace
                if (m_numParticles == m_particles.size())
                    m_particles.push_back(Particle());

                // Emit the particle
                Emit(&m_particles[m_numParticles]);

                // Update particle counter
                m_numParticles ++;

                m_spawnTimer -= m_spawnTime;
            }
            // Update system life
            m_life -= elapsedTime;
        }
    }
}

void ParticleSystem::Render(sf::RenderWindow& renderer)
{
    // Render all particles

    for (sf::Uint32 i = 0; i < m_numParticles; ++i)
    {
        if (m_particles[i].m_life > 0.0f)
            renderer.Draw(m_particles[i].m_sprite);
    }

}

void ParticleSystem::SetLife(float life)
{
    m_life = life;
}

const float ParticleSystem::GetWind() const
{
    return m_gravity.x;
}

void ParticleSystem::SetWind(float wind)
{
    m_gravity.x = -wind;
}

const float ParticleSystem::GetGravity() const
{
    return m_gravity.y;
}

void ParticleSystem::SetGravity(float gravity)
{
    m_gravity.y = gravity;
}

// Emits a particle
void ParticleSystem::Emit(Particle* particle)
{
    particle->m_position = m_position;

    particle->m_velocity = Vector2f(sf::Randomizer::Random(-1.0f, 1.0f * m_gravity.x), sf::Randomizer::Random(-1.0f, 1.0f * m_gravity.y)).Normalize() * 100.0f;

    particle->m_life = 1.f;
    particle->m_sprite.SetPosition(m_position.x, m_position.y);
    particle->m_sprite.SetImage(m_imageResource->Image());
    particle->m_sprite.SetBlendMode(sf::Blend::Add);

}

// Updates a particle
void ParticleSystem::UpdateParticle(Particle* particle, float elapsedTime)
{

    particle->m_life -= elapsedTime;

    particle->m_position += particle->m_velocity * elapsedTime;
    particle->m_sprite.SetColor(sf::Color(particle->m_position.x, particle->m_velocity.y * particle->m_velocity.x, particle->m_position.y * 3.0f));
    particle->UpdateSprite();

}

int ParticleSystem::GetNumParticles() const
{

    return m_numParticles;

}

bool ParticleSystem::IsAlive() const
{

    return (m_life > 0.0f) || (m_numParticles > 0);

}

}; // Graphics
}; // Metgine


